﻿using Engine.Material.Deferred;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using PloobsEngine;
using PloobsEngine.Cameras;
using PloobsEngine.Commands;
using PloobsEngine.Features;
using PloobsEngine.Input;
using PloobsEngine.Light;
using PloobsEngine.Material;
using PloobsEngine.Modelo;
using PloobsEngine.Physics;
using PloobsEngine.Physics.Bepu;
using PloobsEngine.SceneControl;
using PloobsEngineDemo3;

namespace Etapa1.Screens
{
    /// <summary>
    /// Reflexao e Reflexao Planar Screen
    /// </summary>
    public class PlanarReflectionRefractionScreen : SceneScreen
    {
        private BepuPhysicWorld physicWorld;
        private BrutalForceWorld mundo;
        private EngineStuff engine;        
        ICamera cam;

        public PlanarReflectionRefractionScreen(EngineStuff es)
        {
            this.engine = es;
            physicWorld = new BepuPhysicWorld();
            mundo = new BrutalForceWorld(physicWorld);                                    
        }
        
        public override void LoadContent(EngineStuff es)
        {            
            InputAdvanced inp = new InputAdvanced(engine);
            engine.AddComponent(inp);

            base.LoadContent(es);            

            #region Models
            ///Reflexao
            {
                ///Carrega um modelo
                IModelo sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\white");
                sm.LoadModelo();

                ///Cria uma matriz de transformacao
                Matrix trans = Matrix.CreateRotationX(MathHelper.ToRadians(45));
                ///Cria um plano simples (plano x,z) e o transforma usando a matriz criada 
                Plane plano = Plane.Transform(new Plane(0, 1, 0, 0), trans);
                ///Cria uma Caixa (Objeto fisico) que estara contido no plano
                IPhysicObject pi = new BoxObject(new Vector3(1, 1, 1), trans, 1, 100, new Vector3(100, 5, 100));
                pi.isMotionLess = true;
                ///Cria o Shader de reflexao (Passando o plano de reflexao que sera utilizado)
                ///O modelo criado sera um espelho (o quao refletor ele sera depende do shader.InterpolatorColorFactor  e do shader.DistorcionType )
                ///O plano de reflexao (de certa forma, o posicionamento do espelho) é definido pelo objeto plano
                ///Pode-se posicionar o plano em um local e o Objeto em outro, para por exemplo criar uma camera de vigilancia
                PlanarReflection shader = new PlanarReflection(300, 300, plano, 1);
                shader.InterpolatorColorFactor = 0.5f;
                shader.DistorcionType = DistorcionType.Perfect;
                shader.Initialize();

                ///Cria o material
                IMaterial mat = new Material(shader);
                IObject obj4 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj4);

            }


            ///Refracao (Bastante similar ao anterior, porem o objeto comportara como um vidro)
            {
                IModelo sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\white");
                sm.LoadModelo();
                Matrix trans = Matrix.CreateRotationX(MathHelper.ToRadians(45)) * Matrix.CreateTranslation(new Vector3(300,0,0));
                Plane plano = Plane.Transform(new Plane(0, 1, 0, 0), trans);
                IPhysicObject pi = new BoxObject(new Vector3(1, 1, 1), trans, 1, 100, new Vector3(100, 5, 100));
                pi.isMotionLess = true;
                GlassShader shader = new GlassShader(300, 300, plano);                
                shader.Initialize();
                IMaterial mat = new Material(shader);
                IObject obj4 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj4);

            }



            

            #endregion            

            cam = new CameraFirstPerson(true);            
            cam.FarPlane = 3000;

            LightThrowBepu lt = new LightThrowBepu(mundo, engine);         

            #region NormalLight
            DirectionalLight ld1 = new DirectionalLight(Vector3.Left, Color.White);
            DirectionalLight ld2 = new DirectionalLight(Vector3.Right, Color.White);
            DirectionalLight ld3 = new DirectionalLight(Vector3.Backward, Color.White);
            DirectionalLight ld4 = new DirectionalLight(Vector3.Forward, Color.White);
            DirectionalLight ld5 = new DirectionalLight(Vector3.Down, Color.White);
            float li = 0.4f;
            ld1.LightIntensity = li;
            ld2.LightIntensity = li;
            ld3.LightIntensity = li;
            ld4.LightIntensity = li;
            ld5.LightIntensity = li;
            mundo.AddLight(ld1);
            mundo.AddLight(ld2);
            mundo.AddLight(ld3);
            mundo.AddLight(ld4);
            mundo.AddLight(ld5);
            #endregion

            ////Criacao de uma Tecnica
            DeferredRenderTechnic dr = new DeferredRenderTechnic(engine);
            
            IRenderTechnic[] rt = new IRenderTechnic[] { dr };
            this.RenderTechnics = rt;
            dr.RestoreDepth = RestoreDepthOption.NONE;
            dr.DeferredFinalCombination.SaveToTexture = false;
            mundo.AddCamera(cam);
            this.World = mundo;

            ///Adiciona o Componente de Skybox (Funcionamento semelhante ao do Componente de Input)
            Skybox sk = new Skybox(engine);
            engine.AddComponent(sk);

            ///Envia uma mensagem para o Compoente, setando qual sera o SkyBox
            SkyBoxUpdateParametersCommand su = new SkyBoxUpdateParametersCommand(cam, "..\\Content\\Textures\\sunny");            
            CommandProcessor.getCommandProcessor().SendCommandAssyncronous(su);
        }
    }
}

